package cn.seaboot.admin.flake.manager;

import cn.seaboot.admin.flake.bean.*;
import cn.seaboot.admin.flake.service.*;
import cn.seaboot.commons.core.CommonUtils;
import cn.seaboot.flake.exec.FlackException;
import cn.seaboot.flake.mapping.*;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.type.JdbcType;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 映射查询类
 *
 * @author Mr.css
 * @version 2022-02-15 16:25
 */
@Service
public class DefaultMappingProvider implements MappingProvider {

    @Resource
    private FlakeMapperService flakeMapperService;

    @Resource
    private FlakeParamMapService flakeParamMapService;

    @Resource
    private FlakeParamMappingService flakeParamMappingService;

    @Resource
    private FlakeResultMapService flakeResultMapService;

    @Resource
    private FlakeResultMappingService flakeResultMappingService;

    /**
     * 返回完整的{#link Mapper}数据信息，业务上不再验证字段是否为空
     *
     * @param group 映射分组
     * @param id    配置ID
     * @return 映射信息
     */
    @Override
    public Mapper queryMapperById(String group, String id) {
        FlakeMapper flakeMapper = flakeMapperService.queryById(id);
        Mapper mapper = new Mapper();
        mapper.setDatabaseId(flakeMapper.getDatabaseId());
        mapper.setMapperGroup(flakeMapper.getMapperGroup());
        mapper.setId(flakeMapper.getId());

        mapper.setCommandType(flakeMapper.getCommandType());
        mapper.setStatementType(flakeMapper.getStatementType());
        mapper.setTemplate(flakeMapper.getTemplate());

        // parameter
        mapper.setParameterType(flakeMapper.getParameterType());
        if (!"map".equalsIgnoreCase(mapper.getParameterType())) {
            String parameterId = flakeMapper.getParameterMap();
            mapper.setParameterMap(this.queryParameterMapById(parameterId));
        }

        // result
        mapper.setResultType(flakeMapper.getResultType());
        if (!"map".equalsIgnoreCase(flakeMapper.getResultType())) {
            String resultId = flakeMapper.getResultMap();
            mapper.setResultMap(this.queryResultMapById(resultId));
        }
        return mapper;
    }

    /**
     * 返回完整的参数映射，字段信息必须完整{@link ParameterMap#getParameterMappings()}
     *
     * @param parameterId 参数类型
     * @return 参数映射
     */
    @Override
    public ParameterMap queryParameterMapById(String parameterId) {
        FlakeParamMap flakeParamMap = flakeParamMapService.queryById(parameterId);

        ParameterMap parameterMap = new ParameterMap();
        parameterMap.setId(parameterId);

        //type
        Class<?> type = this.getJavaType(flakeParamMap.getType());
        parameterMap.setType(type);

        List<ParameterMapping> mappingList = this.queryParameterMappingById(parameterId);
        parameterMap.setParameterMappings(mappingList);
        return parameterMap;
    }

    /**
     * 返回参数映射明细
     *
     * @param parameterId 参数类型
     * @return 参数映射
     */
    @Override
    public List<ParameterMapping> queryParameterMappingById(String parameterId) {
        List<FlakeParamMapping> list = flakeParamMappingService.queryList(parameterId);
        if (CommonUtils.isEmpty(list)) {
            return Collections.emptyList();
        } else {
            List<ParameterMapping> res = new ArrayList<>();
            for (FlakeParamMapping ret : list) {
                ParameterMapping parameterMapping = new ParameterMapping();
                parameterMapping.setProperty(ret.getProperty());
                parameterMapping.setNumericScale(ret.getNumericScale());
                parameterMapping.setExpression(ret.getExpression());

                parameterMapping.setJavaType(this.getJavaType(ret.getJavaType()));
                parameterMapping.setJdbcType(this.getJdbcType(ret.getJdbcType()));
                parameterMapping.setMode(this.getParameterMode(ret.getMode()));
                res.add(parameterMapping);
            }
            return res;
        }
    }

    /**
     * 返回完整的结果映射，字段信息必须完整{@link ResultMap#getResultMappings()}
     *
     * @param resultId 结果类型
     * @return 结果映射
     */
    @Override
    public ResultMap queryResultMapById(String resultId) {
        FlakeResultMap ret = flakeResultMapService.queryById(resultId);
        ResultMap parameterMap = new ResultMap();
        List<ResultMapping> mappingList = this.queryResultMappingById(resultId);
        parameterMap.setResultMappings(mappingList);
        parameterMap.setId(resultId);

        //type
        Class<?> type = this.getJavaType(ret.getType());
        parameterMap.setType(type);
        return parameterMap;
    }

    /**
     * 返回完整的结果映射
     *
     * @param resultMap 结果类型
     * @return 结果映射
     */
    @Override
    public List<ResultMapping> queryResultMappingById(String resultMap) {
        List<FlakeResultMapping> list = flakeResultMappingService.queryList(resultMap);
        if (CommonUtils.isEmpty(list)) {
            return Collections.emptyList();
        } else {
            List<ResultMapping> res = new ArrayList<>();
            for (FlakeResultMapping ret : list) {
                ResultMapping resultMapping = new ResultMapping();
                resultMapping.setProperty(ret.getProperty());

                resultMapping.setJavaType(this.getJavaType(ret.getJavaType()));
                resultMapping.setJdbcType(this.getJdbcType(ret.getJdbcType()));
                res.add(resultMapping);
            }
            return res;
        }
    }

    private Class<?> getJavaType(String type) {
        try {
            if (type != null) {
                return Class.forName(type);
            } else {
                return null;
            }
        } catch (ClassNotFoundException e) {
            throw new FlackException("Not found class!", e);
        }
    }

    private JdbcType getJdbcType(String jdbcType) {
        if (jdbcType != null) {
            return JdbcType.valueOf(jdbcType);
        }
        return null;
    }


    private ParameterMode getParameterMode(String mode) {
        if (mode != null) {
            return ParameterMode.valueOf(mode);
        }
        return null;
    }
}




